package com.xh.demo.config;

import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.cloud.sentinel.custom.SentinelDataSourceHandler;
import com.alibaba.cloud.sentinel.datasource.RuleType;
import com.alibaba.cloud.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.stream.Stream;

/**
 * @author wen
 * @apiNote SentinelDataSourceAutoConfiguration
 * 等同于 application.yml.blk 的 spring.cloud.sentinel.datasource配置
 * @since 2021-12-14
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelDataSourceAutoConfiguration {

    @Autowired
    private NacosConfigProperties nacosConfigProperties;
    @Value("${spring.application.name:''}")
    private String applicationName;

    @Bean
    public SentinelDataSourceHandler sentinelDataSourceHandler(DefaultListableBeanFactory beanFactory,
                                                               SentinelProperties sentinelProperties,
                                                               Environment env) {
        Map<String, DataSourcePropertiesConfiguration> datasource = sentinelProperties.getDatasource();
        datasource.clear();
        Stream.of(SentinelRuleTypeEnum.values())
                .forEach(ruleType -> {
                    DataSourcePropertiesConfiguration configuration = new DataSourcePropertiesConfiguration();
                    NacosDataSourceProperties properties = new NacosDataSourceProperties();
                    properties.setServerAddr(nacosConfigProperties.getServerAddr());
                    properties.setNamespace(nacosConfigProperties.getNamespace());
                    properties.setUsername(nacosConfigProperties.getUsername());
                    properties.setPassword(nacosConfigProperties.getPassword());
                    properties.setDataId((StringUtils.isEmpty(applicationName) ? nacosConfigProperties.getGroup()
                            : applicationName).concat(SentinelRuleTypeEnum.DASHED).concat(ruleType.getName()));
                    properties.setGroupId(SentinelRuleTypeEnum.SENTINEL_GROUP);
                    properties.setRuleType(ruleType.getRuleType());
                    configuration.setNacos(properties);
                    datasource.put(ruleType.getName(), configuration);
                });
        return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
    }

    public enum SentinelRuleTypeEnum {

        FLOW_RULES("flow-rules", RuleType.FLOW),

        DEGRADE_RULES("degrade-rules", RuleType.DEGRADE),

        SYSTEM_RULES("system-rules", RuleType.SYSTEM),

        AUTHORITY_RULES("authority-rules", RuleType.AUTHORITY),

        PARAM_FLOW_RULES("param-flow-rules", RuleType.PARAM_FLOW);

        private final String name;

        private final RuleType ruleType;

        public final static String DASHED = "-";

        public final static String SENTINEL_GROUP = "SENTINEL_GROUP";

        SentinelRuleTypeEnum(String name, RuleType ruleType) {
            this.name = name;
            this.ruleType = ruleType;
        }

        public String getName() {
            return name;
        }

        public RuleType getRuleType() {
            return ruleType;
        }
    }

}
